package com.woniu.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniu.entity.Result;
import com.woniu.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.PrintWriter;

/**
 * 登录校验拦截器
 * @author tarnett
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    //白名单
    private static final String WHITE_PATH = "/system/login,/system/logout,/trainer/list/all";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 放行白名单，如果是白名单请求，直接放行
        if(WHITE_PATH.contains(request.getRequestURI())){
            log.debug("请求地址为白名单地址：{}，执行放行操作", request.getRequestURI());
            return true;
        }
        // 2. 获取请求头中的token
        String authorization = request.getHeader("Authorization");
        // 判断格式
        if(!StringUtils.hasLength(authorization) || !authorization.startsWith("Bearer")){
            log.debug("非法的token，值为：{}", authorization);
            printResult(response, Result.error(40001,"请求中未包含token"));
            return false;
        }
        try {
            // 3. 解析token，判断是否有效
            // 4. token有效，放行
            String token = authorization.substring(7);
            Claims claims = JwtUtil.parseJWT(token);
            String username = claims.get("username").toString();

            // 先redis中获取token，如果redis中的token不存在 根据key去获取value
            String redisToken = stringRedisTemplate.opsForValue().get("token-" + username);
            if(redisToken == null){
                printResult(response, Result.error(40001,"登录失效了"));
                return false;
            }
            if(!token.equals(redisToken)){
                printResult(response, Result.error(40001,"token被篡改了"));
                return false;
            }


            // 把username保存起来（ThreadLocal-本地线程栈）
            // 将username存到本地线程里面
            AuthenticationContextHolder.setContext(username);

            return true;
        }catch (Exception exception){
            // 5. token无效，直接返回
            exception.printStackTrace();
            // 抛出异常，说明token解析失败
            printResult(response, Result.error(40001,"非法的token"));
            return false;

        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 如果不删除本地线程中的数据，可能会造成内存泄露
        AuthenticationContextHolder.clearContext();
    }

    /**
     * 打印错误的JSON响应数据
     * @param response
     * @param result
     */
    private void printResult(HttpServletResponse response, Result result){
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try (PrintWriter writer = response.getWriter()) {
            ObjectMapper objectMapper = new ObjectMapper();
            String messageResult = objectMapper.writeValueAsString(result);
            writer.print(messageResult);
        } catch (Exception e) {
            log.debug("login token error is {}", e.getMessage());
        }
    }
}